package com.xx.happychatboot.middleware.netty.handller;

import cn.hutool.core.net.url.UrlBuilder;
import com.xx.happychatboot.base.utils.RedisUtils;
import com.xx.happychatboot.middleware.netty.channel.WebSocketChannelMap;
import com.xx.happychatboot.middleware.netty.constants.WebSocketConstants;
import com.xx.happychatboot.middleware.netty.constants.WebSocketRedisConstants;
import com.xx.happychatboot.middleware.netty.utils.NettyUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

import java.util.Objects;
import java.util.Optional;
@Slf4j
public class MyHeaderCollectHandler extends ChannelInboundHandlerAdapter {
    /**
     * 从Http请求中获取token并放到netty attribute中
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        // 自定义HTTP请求处理
        if (msg instanceof HttpObject) {
            final HttpObject httpObject = (HttpObject) msg;
            if (httpObject instanceof HttpRequest) {
                HttpRequest request = (HttpRequest) msg;
                UrlBuilder urlBuilder = UrlBuilder.ofHttp(request.uri());
                Optional<String> tokenOptional = Optional.of(urlBuilder)
                        .map(UrlBuilder::getQuery)
                        .map(k -> k.get("access_token"))//获取token
                        .map(CharSequence::toString);//字符序列化成string
                //判断token是否存在 存在则写入channel中
                tokenOptional.ifPresent(token -> NettyUtils.setAttr(ctx.channel(), NettyUtils.TOKEN, token));
                // 替换request url
                request.setUri(urlBuilder.getPath().toString());
            }
        }
        // 继续其他的解析器
        ctx.fireChannelRead(msg);
    }

    /**
     * 心跳检测处理
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                // 在规定时间内没有收到客户端的上行数据, 主动断开连接
                AttributeKey<Long> attr = AttributeKey.valueOf("USER_ID");
                Long userId = ctx.channel().attr(attr).get();
                log.info("心跳超时，即将断开连接,用户id:{} ", userId);
                ctx.channel().close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }

    }

    /**
     * 处理断开连接
     * @param ctx
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) {
        AttributeKey<Long> userIdAttr = AttributeKey.valueOf(WebSocketConstants.USER_ID);
        Long userId = ctx.channel().attr(userIdAttr).get();
        Channel channel = WebSocketChannelMap.getChannel(userId);
        if (Objects.nonNull(channel)) {
            WebSocketChannelMap.removeChannelCtx(userId);
            // 清除掉redis中的信息
            String key = WebSocketRedisConstants.WEB_SOCKET_USER_SERVER_ID + userId;
            RedisUtils.del(key);
            log.info("断开连接,userId:{},{}", userId, ctx.channel().id().asLongText());
        }
    }
}
